"""
# -*- coding: utf-8 -*-
# @Time    : 2023/5/30 9:33
# @Author  : 王摇摆
# @FileName: Simple.py
# @Software: PyCharm
# @Blog    ：https://blog.csdn.net/weixin_44943389?type=blog
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import warnings

from Pocket.Simple.Data import createTrainDatasWithNoise, buildLine
from Pocket.Simple.Pocket_Manual import errorIndexes

warnings.filterwarnings('ignore')
plt.rcParams['font.sans-serif'] = ['Microsoft yaHei']  # 选择一个本地的支持中文的字体

start = -10
end = 10
W = np.array([2, 5])
X, y = createTrainDatasWithNoise(W, start, end)
x1 = X[y > 0][:, 0]
y1 = X[y > 0][:, 1]
x2 = X[y < 0][:, 0]
y2 = X[y < 0][:, 1]

import numpy as np


def pocketReturn(X, y, iteration, maxIterNoChange=5):
    """
    口袋算法实现
    args:
        X - 训练数据集
        y - 目标标签值
        iteration - 最大迭代次数
    return:
        Ws - 权重系数数组
        tmpWs - 临时权重系数数组
        errorCounts - 权重系数错误数数组
        tmpErrorCounts - 临时权重系数错误数数组
    """
    np.random.seed(42)
    # 初始化权重系数
    W = np.zeros(X.shape[1])
    Ws = np.array([W])
    tmpWs = np.array([W])
    # 获取错误点的下标集合
    errors = errorIndexes(W, X, y)
    errorCounts = np.array([len(errors)])
    tmpErrorCounts = np.array([len(errors)])
    iterNoChange = 0
    # 循环
    for i in range(iteration):
        iterNoChange = iterNoChange + 1
        # 随机获取错误点下标
        errorIndex = np.random.randint(0, len(errors))
        # 计算临时权重系数
        tmpW = W + y[errors[errorIndex]] * X[errorIndex]
        # 获取临时权重系数下错误点的下标集合
        tmpErrors = errorIndexes(tmpW, X, y)
        # 如果错误点数量更少，就更新权重系数
        if len(errors) >= len(tmpErrors):
            iterNoChange = 0
            # 修正权重系数
            W = tmpW
            errors = tmpErrors
        Ws = np.insert(Ws, len(Ws), values=W, axis=0)
        tmpWs = np.insert(tmpWs, len(tmpWs), values=tmpW, axis=0)
        errorCounts = np.insert(errorCounts, len(errorCounts), values=len(errors), axis=0)
        tmpErrorCounts = np.insert(tmpErrorCounts, len(tmpErrorCounts), values=len(tmpErrors), axis=0)
        if iterNoChange >= maxIterNoChange:
            break
    return Ws, tmpWs, errorCounts, tmpErrorCounts


Ws, tmpWs, errorCounts, tmpErrorCounts = pocketReturn(X, y, 50)
fig = plt.figure()
plt.title('口袋算法')
plt.scatter(x1, y1, c='b', marker='o', s=20)
plt.scatter(x2, y2, c='r', marker='o', s=20)
line, = plt.plot(0, 0, markersize=0, label='W')
tmpLine, = plt.plot(0, 0, markersize=0, label='Temp W')


def update(i):
    x3, y3 = buildLine(Ws[i], start, end)
    x4, y4 = buildLine(tmpWs[i], start, end)
    line.set_data(x3, y3)
    line.set_label("W: %d 个错误点" % (errorCounts[i]))
    tmpLine.set_data(x4, y4)
    tmpLine.set_label("Temp W: %d 个错误点" % (tmpErrorCounts[i]))
    plt.legend(loc="upper right")
    return line, tmpLine,


ani = animation.FuncAnimation(fig, update, range(0, len(Ws)), interval=1000, blit=True, repeat=False)
ani.save('pocket_simple.gif')
plt.legend(loc="upper right")
plt.show()
